﻿/*
 * Created by SharpDevelop.
 * User: ratul
 * Date: 3/5/2010
 * Time: 2:07 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using H264Impl.NET.Coding;

namespace H264Impl.NET.NAL.NonVCLNALUnit
{
	/// <summary>
	/// Description of SequenceParameterSet.
	/// </summary>
	public class SequenceParameterSetNonVCLNALUnit : NALUnit
	{
		public SequenceParameterSetNonVCLNALUnit(BitStream _NALUnitBitStream, bool forbiddenZeroBit, UInt32 _NALRefID) : base(_NALUnitBitStream, forbiddenZeroBit, _NALRefID, 0)
		{
			parseRBSP();
		}
		
		protected void parseRBSP()
		{
			profileIDC = (Byte)(RBSP.getBits(8));
			constraintSet0Flag = RBSP.getBit();
			constraintSet1Flag = RBSP.getBit();
			constraintSet2Flag = RBSP.getBit();
			constraintSet3Flag = RBSP.getBit();
			constraintSet4Flag = RBSP.getBit();
			reservedZero3Bits = RBSP.getBits(3);
			
			levelIDC = (Byte)(RBSP.getBits(8));
			SeqParameterSetId = ExpGolomb.getUnsignedIntegerElement(RBSP);
			
			if(profileIDC == 100 || profileIDC == 110 || profileIDC == 110  || profileIDC == 122 || profileIDC == 244 || profileIDC == 44 || profileIDC == 83 || profileIDC == 86 || profileIDC == 118)
			{
				chromaFormatIdc = (Byte)(RBSP.getBits(8));
				if(chromaFormatIdc == 3)
					separateColorPlaneFlag = RBSP.getBit();
				bitDepthLumaMinus8 = ExpGolomb.getUnsignedIntegerElement(RBSP);
				bitDepthChromaMinus8 = ExpGolomb.getUnsignedIntegerElement(RBSP);
				qpPrimeYZeroTransformBypassFlag = RBSP.getBit();
				seqScalingMatrixPresentFlag = RBSP.getBit();
				
				if(seqScalingMatrixPresentFlag)
				{
					seqScalingListPresentFlag = new bool[((chromaFormatIdc != 3) ? 8 : 12 )];
					for(int i=0; i<((chromaFormatIdc != 3) ? 8 : 12 ); i++) 
					{
						seqScalingListPresentFlag[i] = RBSP.getBit();
						if(seqScalingListPresentFlag[i])
						{
							if(i<6)
								;//scalingList();
							else 
								;//scalingList();
						}
					}
				}
				
			}
			
			log2MaxFameNumMinus4 = ExpGolomb.getUnsignedIntegerElement(RBSP);
			picOrderCntType = ExpGolomb.getUnsignedIntegerElement(RBSP);
			if(picOrderCntType == 0)
				log2MaxPicOrderCntLsbMinus4 = ExpGolomb.getUnsignedIntegerElement(RBSP);
			else if(picOrderCntType == 1)
			{
				deltaPicOrderAlwaysZeroFlag = RBSP.getBit();
				offsetForNonRefPic = ExpGolomb.getSignedIntegerElement(RBSP);
				offsetForTopToBottomField = ExpGolomb.getSignedIntegerElement(RBSP);
				numRefFamesInPicOrderCntCycle = ExpGolomb.getUnsignedIntegerElement(RBSP);
				offsetForRefFrame = new List<Int32>((int)(numRefFamesInPicOrderCntCycle));
				for(int i=0;i<numRefFamesInPicOrderCntCycle; i++)
					offsetForRefFrame[0] = ExpGolomb.getSignedIntegerElement(RBSP);
			}
			
			maxNumRefFrames = ExpGolomb.getUnsignedIntegerElement(RBSP);
			gapsInFrameNumValueAllowedflag = RBSP.getBit();
			picWidthInMbsMinus1 = ExpGolomb.getUnsignedIntegerElement(RBSP);
			picHeightInMapUnitsMinus1 = ExpGolomb.getUnsignedIntegerElement(RBSP);
			
			frameMbsOnlyFlag = RBSP.getBit();
			if(!frameMbsOnlyFlag)
				mbAdaptiveFrameFieldFlag = RBSP.getBit();
			direct8x8InferenceFlag = RBSP.getBit();
			
			frameCroppingFlag = RBSP.getBit();
			if(frameCroppingFlag)
			{
				frameCropLeftOffset = ExpGolomb.getUnsignedIntegerElement(RBSP);
				frameCropRightOffset = ExpGolomb.getUnsignedIntegerElement(RBSP);
				frameCropTopOffset = ExpGolomb.getUnsignedIntegerElement(RBSP);
				frameCropBottomOffset = ExpGolomb.getUnsignedIntegerElement(RBSP);
			}
			
			vuiParametersPresentFlag = RBSP.getBit();
			if(vuiParametersPresentFlag)
				vuiParameters();
			
			rbspTrailingBits();
		}
		
		void rbspTrailingBits()
		{
			
		}
		
		private void vuiParameters()
		{
			aspectRatioInfoPresentFlag = RBSP.getBit();
			if( aspectRatioInfoPresentFlag ) 
			{
				aspectRatioIdc = (Byte)(RBSP.getBits(8));
				if( aspectRatioIdc == (byte)(SampleRatioAspect.RExtended_SAR) )
				{
					sarWidth = (UInt16)(RBSP.getBits(16));
					sarHeight = (UInt16)(RBSP.getBits(16));
					
				}
			}
			overscanInfoPresentFlag = RBSP.getBit();
			if( overscanInfoPresentFlag )
				overscanAppropriateFlag = RBSP.getBit();
			videoSignalTypePresentFlag = RBSP.getBit();
			if( videoSignalTypePresentFlag )
			{
				videoFormat = (Byte)(RBSP.getBits(8));
				videoFullRangeFlag = RBSP.getBit();
				colourDescriptionpresentFlag = RBSP.getBit();
				if( colourDescriptionpresentFlag )
				{
					colourPrimaries = (Byte)(RBSP.getBits(8));
					transferCharacteristics = (Byte)(RBSP.getBits(8));
					matrixCoefficients = (Byte)(RBSP.getBits(8));
				}
			}
			
			chromaLocInfoPresentFlag = RBSP.getBit();
			if( chromaLocInfoPresentFlag ) 
			{
				chromaSampleLocTypeTopField = ExpGolomb.getUnsignedIntegerElement(RBSP);
				chromaSampleLocTypeBottomField = ExpGolomb.getUnsignedIntegerElement(RBSP);
			}
			timingInfoPresentFlag = RBSP.getBit();
			if( timingInfoPresentFlag )
			{
				numUnitsinTick = RBSP.getBits(32);
				timeScale = RBSP.getBits(32);
				fixedFrameRateFlag = RBSP.getBit();
			}
			nalHrdParametersPresentFlag = RBSP.getBit();
			if( nalHrdParametersPresentFlag )
				hrd_parameters( );
			vclHrdParametersPresentFlag = RBSP.getBit();
			if( vclHrdParametersPresentFlag )
				hrd_parameters( );
			if( nalHrdParametersPresentFlag || vclHrdParametersPresentFlag )
				lowDelayHrdFlag = RBSP.getBit();
			picStructPresentFlag = RBSP.getBit();
			bitstreamRestrictionFlag = RBSP.getBit();
			if( bitstreamRestrictionFlag )
			{
				motionVectorsOverPicBoundariesFlag = RBSP.getBit();
				maxBytesPerPicDenom = ExpGolomb.getUnsignedIntegerElement(RBSP);
				maxBitsPerMbDenom = ExpGolomb.getUnsignedIntegerElement(RBSP);
				log2MaxMvLengthHorizontal = ExpGolomb.getUnsignedIntegerElement(RBSP);
				log2MaxMvLengthVertical = ExpGolomb.getUnsignedIntegerElement(RBSP);
				numReorderFrames = ExpGolomb.getUnsignedIntegerElement(RBSP);
				maxDecFrameBuffering = ExpGolomb.getUnsignedIntegerElement(RBSP);
			}
					
		}
		
		enum SampleRatioAspect
		{
			R1_1 = 1,
			R12_11,
			R10_11,
			R16_11,
			R40_33,
			R24_11,
			R20_11,
			R32_11,
			R80_33,
			R18_11,
			R15_11,
			R64_33,
			R160_99,
			R4_3,
			R3_2,
			R2_1,
			RExtended_SAR = 255	
		}
		
		private void hrd_parameters( ) 
		{
			cpbCntMinus1 = ExpGolomb.getUnsignedIntegerElement(RBSP);
			bitRateScale = (Byte)(RBSP.getBits(8));
			cpbSizeScale = (Byte)(RBSP.getBits(8));
				
			bitRateValueMinus1 = new UInt32[cpbCntMinus1+1];
			cpbSizeValueMinus1 = new UInt32[cpbCntMinus1+1];
			cbrFlag = new bool[cpbCntMinus1+1];
			for( int SchedSelIdx = 0; SchedSelIdx <= cpbCntMinus1; SchedSelIdx++ ) {
				bitRateValueMinus1[ SchedSelIdx ] = ExpGolomb.getUnsignedIntegerElement(RBSP);
				cpbSizeValueMinus1[ SchedSelIdx ] = ExpGolomb.getUnsignedIntegerElement(RBSP);
				cbrFlag[ SchedSelIdx ] = RBSP.getBit();
			}
			initialCpbRemovalDelayLengthMinus1 = (Byte)(RBSP.getBits(8));
			cpbRemovalDelayLengthMinus1 = (Byte)(RBSP.getBits(8));
			dpbOutputDelayLengthMinus1 = (Byte)(RBSP.getBits(8));
			timeOffsetLength = (Byte)(RBSP.getBits(8));
		}
		
		
		protected void scalingList( out UInt32[] scalingList1, UInt32 sizeOfScalingList, out bool useDefaultScalingMatrixFlag )
		{ 
			UInt32 lastScale = 8;
			UInt32 nextScale = 8;
			
			
			useDefaultScalingMatrixFlag = false; 
			
			scalingList1 = new UInt32[sizeOfScalingList];
			for( int j = 0; j < sizeOfScalingList; j++ ) 
			{
				if( nextScale != 0 )
				{
					deltaScale = ExpGolomb.getSignedIntegerElement(RBSP);
					nextScale = (UInt32)(( lastScale + deltaScale + 256 ) % 256);
					if( j == 0 && nextScale == 0 )
						useDefaultScalingMatrixFlag = true;
					else
						useDefaultScalingMatrixFlag = false;
				}
				scalingList1[j] = ( nextScale == 0 ) ? lastScale : nextScale;
				lastScale = scalingList1[j];
			}	
		}
		
		
		
		protected byte profileIDC;
		
		bool constraintSet0Flag;
		bool constraintSet1Flag;
		bool constraintSet2Flag;
		bool constraintSet3Flag;
		bool constraintSet4Flag;
		UInt32 reservedZero3Bits;
		
		byte levelIDC;
		UInt32 SeqParameterSetId;
		protected UInt32 chromaFormatIdc;
		bool separateColorPlaneFlag;
		UInt32 bitDepthLumaMinus8;		
		UInt32 bitDepthChromaMinus8;
		bool qpPrimeYZeroTransformBypassFlag;
		bool seqScalingMatrixPresentFlag;
		bool[] seqScalingListPresentFlag;
		Int32 deltaScale;
		
		UInt32 log2MaxFameNumMinus4;
		UInt32 picOrderCntType;
		UInt32 log2MaxPicOrderCntLsbMinus4;
		bool deltaPicOrderAlwaysZeroFlag;
		Int32 offsetForNonRefPic;
		Int32 offsetForTopToBottomField;
		UInt32 numRefFamesInPicOrderCntCycle;
		List<Int32> offsetForRefFrame;
		UInt32 maxNumRefFrames;
		bool gapsInFrameNumValueAllowedflag;
		UInt32 picWidthInMbsMinus1;
		UInt32 picHeightInMapUnitsMinus1;
		
		bool frameMbsOnlyFlag;
		bool mbAdaptiveFrameFieldFlag;
		bool direct8x8InferenceFlag;
		bool frameCroppingFlag;
		UInt32 frameCropLeftOffset;
		UInt32 frameCropRightOffset;
		UInt32 frameCropTopOffset;
		UInt32 frameCropBottomOffset;
		bool vuiParametersPresentFlag;
		
		
		
		//VUI parameters
		bool aspectRatioInfoPresentFlag;
		byte aspectRatioIdc;
		UInt16 sarWidth;
		UInt16 sarHeight;
		bool overscanInfoPresentFlag;
		bool overscanAppropriateFlag;
		bool videoSignalTypePresentFlag;
		byte videoFormat;
		bool videoFullRangeFlag;
		bool colourDescriptionpresentFlag;
		byte colourPrimaries;
		byte transferCharacteristics;
		byte matrixCoefficients;
		
		bool chromaLocInfoPresentFlag;
		UInt32 chromaSampleLocTypeTopField;
		UInt32 chromaSampleLocTypeBottomField;
		bool timingInfoPresentFlag;
		UInt32 numUnitsinTick;
		UInt32 timeScale;
		bool fixedFrameRateFlag;
		bool nalHrdParametersPresentFlag;
		bool vclHrdParametersPresentFlag;
		bool lowDelayHrdFlag;
		bool picStructPresentFlag;
		bool bitstreamRestrictionFlag;
		
		bool motionVectorsOverPicBoundariesFlag;
		UInt32 maxBytesPerPicDenom;
		UInt32 maxBitsPerMbDenom;
		UInt32 log2MaxMvLengthHorizontal;
		UInt32 log2MaxMvLengthVertical;
		UInt32 numReorderFrames;
		UInt32 maxDecFrameBuffering;
		
							
		
		
		//HRD parameters
		UInt32 cpbCntMinus1;
		byte bitRateScale;
		byte cpbSizeScale;
		UInt32[] bitRateValueMinus1;
		UInt32[] cpbSizeValueMinus1;
		bool[] cbrFlag;
		byte initialCpbRemovalDelayLengthMinus1;
		byte cpbRemovalDelayLengthMinus1;
		byte dpbOutputDelayLengthMinus1;
		byte timeOffsetLength;
			
		
	}
}
